﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DBComparer.DataAbstract;

using System.Reflection;
using System.Diagnostics;

namespace DBComparer
{
    public partial class frmMain : Form
    {
        DataSet dsChanges = null;

        #region Ctor & Load
        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            #region Get Version From Assembly
            Assembly assembly = Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string version = fvi.ProductVersion;
            this.Text += " " + version;
            lblVersion.Text = version;
            #endregion


            dsChanges = new DataSet();
            dsChanges.Tables.Add();
            dsChanges.Tables[0].Columns.Add("Name");
            dsChanges.Tables[0].Columns.Add("ObjectType");
            dsChanges.Tables[0].Columns.Add("Type");
            dsChanges.Tables[0].Columns.Add("Code");


            dgv.DataSource = dsChanges.Tables[0];




            // ADD Select All BOX
            CheckBox ckBox = new CheckBox();
            Rectangle rect = dgv.GetCellDisplayRectangle(1, -1, true);
            ckBox.Size = new Size(18, 18);
            ckBox.Location = rect.Location;
            ckBox.CheckedChanged += new EventHandler(ckBox_CheckedChanged);
            dgv.Controls.Add(ckBox);

        }

        void ckBox_CheckedChanged(object sender, EventArgs e)
        {
            for (int i = 0; i < dgv.RowCount; i++)
            {
                dgv[0, i].Value = ((CheckBox)sender).Checked;
            }
        }

        #endregion

        #region On Connected
        private void sourceWizard_onConnected(object sender, EventArgs e)
        {
            lblSource.Text = sourceWizard.Server;
            destinationWizard.buttonEnable = true;
        }

        private void destinationWizard_onConnected(object sender, EventArgs e)
        {
            lblDestination.Text = destinationWizard.Server;
        }
        #endregion

        #region On DataBaseSelectIndexChange
        private void sourceWizard_onDataBaseSelectIndexChange(object sender, EventArgs e)
        {
            sourceViews.Connection= sourceFunctions.Connection = ctlSPListSource.Connection = sourceWizard.Connection;
            ctlSPListSource.Reload();
            sourceFunctions.Reload();
            sourceViews.Reload();
        }

        private void destinationWizard_onDataBaseSelectIndexChange(object sender, EventArgs e)
        {
            destinationViews.Connection = destinationFunctions.Connection = ctlSPListDestination.Connection = destinationWizard.Connection;
            
        }
        #endregion

        private void ctlSPListSource_onListLoaded(object sender, EventArgs e)
        {

        }

        private void ctlSPListDestination_onListLoaded(object sender, EventArgs e)
        {
            foreach (string s in ctlSPListSource.Objects.Keys)
            {
                if (!ctlSPListDestination.Objects.Keys.Contains(s))
                {
                    // Add
                    DataRow dr = dsChanges.Tables[0].NewRow();
                    dr["Name"] = s;
                    dr["ObjectType"] = "Stored Procedure";
                    dr["Type"] = "CREATE";
                    dr["Code"] = ctlSPListSource.Objects[s];


                    dsChanges.Tables[0].Rows.Add(dr);
                }
                else
                {
                    // Check for Changes
                    if (Compute(ctlSPListSource.Objects[s], ctlSPListDestination.Objects[s]))
                    {
                        DataRow dr = dsChanges.Tables[0].NewRow();
                        dr["Name"] = s;
                        dr["ObjectType"] = "Stored Procedure";
                        dr["Type"] = "ALTER";
                        dr["Code"] = ctlSPListSource.Objects[s];

                        dsChanges.Tables[0].Rows.Add(dr);
                    }

                }
            }

        }


        private bool Compute(string source, string destination) 
        {
            switch (ctlComputeMode.Mode)
            {
                case ComputeMode.Modes.Basic:
                    // string.Compare

                    if (string.Compare(source, destination) != 0)
                        return true;

                    break;
                case ComputeMode.Modes.Levenshtein:
                    // Levenshtein

                    if (DataAbstract.LevenshteinDistance.Compute(source, destination) > 0)
                        return true;

                    break;
                default:
                    break;
            }


            return false;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void btnApply_Click(object sender, EventArgs e)
        {
            if (dgv.RowCount == 0)
            {
                MessageBox.Show("Compare First");
                return;
            }

            int SelectedRows = 0;

            foreach (DataGridViewRow r in dgv.Rows)
            {
                DataGridViewCheckBoxCell oCell = r.Cells[0] as DataGridViewCheckBoxCell;
                bool bChecked = (null != oCell && null != oCell.Value && 1 == Convert.ToInt32(oCell.Value));
                if (bChecked)
                    SelectedRows++;
            }

            if (SelectedRows==0)
            {
                MessageBox.Show("Select First");
                return;
            }


            if (MessageBox.Show("Are You Sure?", "DBComparer", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes)
            {
                string _result = "";

                foreach (DataGridViewRow r in dgv.Rows)
                {
                    DataGridViewCheckBoxCell oCell = r.Cells[0] as DataGridViewCheckBoxCell;
                    bool bChecked = (null != oCell && null != oCell.Value && 1 == Convert.ToInt32(oCell.Value));

                    if (bChecked)
                    {
                        DataGridViewTextBoxCell titleCell = r.Cells[1] as DataGridViewTextBoxCell;
                        DataGridViewTextBoxCell typeCell = r.Cells[3] as DataGridViewTextBoxCell;

                        DataGridViewTextBoxCell codeCell = r.Cells[4] as DataGridViewTextBoxCell;

                        switch (typeCell.Value.ToString())
                        {
                            case "CREATE":
                                _result = codeCell.Value.ToString();
                                break;
                            case "ALTER":
                                _result = ReplaceCreate(codeCell.Value.ToString());
                                break;
                            case "Applied":
                                return;
                        }

                        new DataAccess.Databases().Run(ctlSPListDestination.Connection.GetConnection(), _result);
                        typeCell.Value = "Applied";
                    }
                }

                dsChanges.Tables[0].Rows.Clear();

                ctlSPListDestination.Reload();
                destinationFunctions.Reload();
                destinationViews.Reload();

            }
        }

        private string ReplaceCreate(string input) 
        {
            input = input.ToUpper();
            input = input.Replace("CREATE PROC", "ALTER PROC");
            input = input.Replace("CREATE VIEW", "ALTER VIEW");
            input = input.Replace("CREATE FUNCTION", "ALTER FUNCTION");

            return input;
        }

        private void destinationFunctions_onListLoaded(object sender, EventArgs e)
        {
            foreach (string s in sourceFunctions.Objects.Keys)
            {
                if (!destinationFunctions.Objects.Keys.Contains(s))
                {
                    // Add
                    DataRow dr = dsChanges.Tables[0].NewRow();
                    dr["Name"] = s;
                    dr["ObjectType"] = "Function";
                    dr["Type"] = "CREATE";
                    dr["Code"] = sourceFunctions.Objects[s];


                    dsChanges.Tables[0].Rows.Add(dr);
                }
                else
                {
                    // Check for Changes
                    if (Compute(sourceFunctions.Objects[s], destinationFunctions.Objects[s]))
                    {
                        DataRow dr = dsChanges.Tables[0].NewRow();
                        dr["Name"] = s;
                        dr["ObjectType"] = "Function";
                        dr["Type"] = "ALTER";
                        dr["Code"] = sourceFunctions.Objects[s];

                        dsChanges.Tables[0].Rows.Add(dr);
                    }

                }
            }

        }

        private void destinationViews_onListLoaded(object sender, EventArgs e)
        {
            foreach (string s in sourceViews.Objects.Keys)
            {
                if (!destinationViews.Objects.Keys.Contains(s))
                {
                    // Add
                    DataRow dr = dsChanges.Tables[0].NewRow();
                    dr["Name"] = s;
                    dr["ObjectType"] = "View";
                    dr["Type"] = "CREATE";
                    dr["Code"] = sourceViews.Objects[s];


                    dsChanges.Tables[0].Rows.Add(dr);
                }
                else
                {
                    // Check for Changes
                    if (Compute(sourceViews.Objects[s], destinationViews.Objects[s]))
                    {
                        DataRow dr = dsChanges.Tables[0].NewRow();
                        dr["Name"] = s;
                        dr["ObjectType"] = "View";
                        dr["Type"] = "ALTER";
                        dr["Code"] = sourceViews.Objects[s];

                        dsChanges.Tables[0].Rows.Add(dr);
                    }

                }
            }

        }

        private void btnCompare_Click(object sender, EventArgs e)
        {
            dsChanges.Tables[0].Rows.Clear();

            string error = "";
            if (sourceWizard.Connection.Check(out error) && destinationWizard.Connection.Check(out error))
            {
                ctlSPListDestination.Reload();
                destinationFunctions.Reload();
                destinationViews.Reload();

                tabs.SelectTab(4);

            } else
                MessageBox.Show(error);

        }

        private void btnSwap_Click(object sender, EventArgs e)
        {

        }

        private void ctlComputeMode_Load(object sender, EventArgs e)
        {
        }

        private void ctlComputeMode_ModeChange(object sender, EventArgs e)
        {
        }

        private void dgv_SelectionChanged(object sender, EventArgs e)
        {
            // JUST PREVIEW CHANGES,

            ctlPreview.Clear();

            if (dgv.SelectedRows.Count > 0)
            {
                switch (dgv.SelectedRows[0].Cells[3].Value.ToString())
                {
                    case "CREATE":

                        switch (dgv.SelectedRows[0].Cells[2].Value.ToString())
	                    {
                            case "Stored Procedure":
                                ctlPreview.SelectedText = ctlSPListSource.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()];
                                break;
                            case "View":
                                ctlPreview.SelectedText = sourceViews.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()];
                                break;
                            case "Function":
                                ctlPreview.SelectedText = sourceFunctions.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()];
                                break;
	                    }
                        
                        break;
                    case "ALTER":

                        switch (dgv.SelectedRows[0].Cells[2].Value.ToString()) 
                        {
                            case "Stored Procedure":
                                FindDifference(ctlSPListSource.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()], ctlSPListDestination.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()]);
                                break;
                            case "View":
                                FindDifference(sourceViews.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()], destinationViews.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()]);
                                break;
                            case "Function":
                                FindDifference(sourceFunctions.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()], sourceFunctions.Objects[dgv.SelectedRows[0].Cells[1].Value.ToString()]);
                                break;
                        }

                        break;
                }
                    

            }


        }

        private void FindDifference(string source, string destination) 
        {
            try
            {
                Diff.Item[] diffs = Diff.DiffText(source, destination, true, true, true);

                string[] sourceLines = source.Split('\n');
                string[] destinationLines = destination.Split('\n');


                int n = 0;
                for (int fdx = 0; fdx < diffs.Length; fdx++)
                {
                    Diff.Item aItem = diffs[fdx];

                    // write unchanged lines
                    while ((n < aItem.StartB) && (n < sourceLines.Length))
                    {
                        ctlPreview.SelectedText = sourceLines[n];
                        n++;
                    } // while

                    // write deleted lines
                    for (int m = 0; m < aItem.deletedA; m++)
                    {
                        ctlPreview.SelectionBackColor = Color.IndianRed;
                        ctlPreview.SelectedText = destinationLines[aItem.StartA + m];
                    } // for

                    // write inserted lines
                    while (n < aItem.StartB + aItem.insertedB)
                    {
                        ctlPreview.SelectionBackColor = Color.GreenYellow;
                        ctlPreview.SelectedText = sourceLines[n];
                        n++;
                    } // while
                } // while

                // write rest of unchanged lines
                while (n < destinationLines.Length)
                {
                    ctlPreview.SelectedText += destinationLines[n];
                    n++;
                } // while

            }
            catch (Exception ex)
            {
                
            }

        }


    }

}